/******************************************************************************* * Copyright (c) 2010 The Eclipse Foundation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * The Eclipse Foundation - initial API and implementation *******************************************************************************/ package org.eclipse.epp.mpc.tests.service; import static org.hamcrest.Matchers.*; import static org.junit.Assume.*; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.net.URL; import java.security.cert.Certificate; import java.text.MessageFormat; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Arrays; import java.util.Date; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.FileLocator; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.NullProgressMonitor; import org.eclipse.core.runtime.Platform; import org.eclipse.epp.internal.mpc.core.MarketplaceClientCore; import org.eclipse.epp.internal.mpc.core.MarketplaceClientCorePlugin; import org.eclipse.epp.internal.mpc.core.ServiceLocator; import org.eclipse.epp.internal.mpc.core.service.DefaultMarketplaceService; import org.eclipse.epp.mpc.core.model.IIu; import org.eclipse.epp.mpc.core.model.IIus; import org.eclipse.epp.mpc.core.model.INode; import org.eclipse.epp.mpc.core.model.ISearchResult; import org.eclipse.epp.mpc.core.service.IMarketplaceUnmarshaller; import org.eclipse.epp.mpc.core.service.QueryHelper; import org.eclipse.epp.mpc.core.service.UnmarshalException; import org.eclipse.epp.mpc.tests.Categories.RemoteTests; import org.eclipse.epp.mpc.tests.LoggingSuite; import org.eclipse.equinox.internal.p2.core.helpers.ServiceHelper; import org.eclipse.equinox.internal.p2.repository.Activator; import org.eclipse.equinox.p2.core.IProvisioningAgent; import org.eclipse.equinox.p2.core.UIServices; import org.hamcrest.Matcher; import org.hamcrest.MatcherAssert; import org.junit.Assert; import org.junit.Before; import org.junit.ClassRule; import org.junit.ComparisonFailure; import org.junit.Ignore; import org.junit.Rule; import org.junit.Test; import org.junit.experimental.categories.Category; import org.junit.rules.ExternalResource; import org.junit.rules.TestRule; import org.junit.rules.TestWatcher; import org.junit.runner.Description; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; import org.junit.runners.Parameterized.Parameter; import org.junit.runners.Parameterized.Parameters; import org.junit.runners.model.Statement; import org.osgi.framework.ServiceRegistration; @RunWith(Parameterized.class) @Category(RemoteTests.class) @Ignore("Disabled until test data on marketplace-staging.eclipse.org can be recreated") public class SolutionCompatibilityFilterTest { private static final String BASE_URL = "http://marketplace-staging.eclipse.org"; public static enum System { WIN32(Platform.OS_WIN32, Platform.WS_WIN32), // LINUX(Platform.OS_LINUX, Platform.WS_GTK), // MACOS(Platform.OS_MACOSX, Platform.WS_COCOA); private final String os; private final String ws; private System(String os, String ws) { this.os = os; this.ws = ws; } public void applyTo(Map<String, String> metaParams) { metaParams.put(DefaultMarketplaceService.META_PARAM_OS, os); metaParams.put(DefaultMarketplaceService.META_PARAM_WS, ws); } } private static final String JAVA_PRODUCT_ID = "epp.package.java"; private static final String SDK_PRODUCT_ID = "org.eclipse.sdk.ide"; public static enum EclipseRelease { UNKNOWN(null, null, null, null), // INDIGO(JAVA_PRODUCT_ID, "1.4.2.20120131-1457", "3.7.0.v20110110", null), // JUNO_3_8(SDK_PRODUCT_ID, "3.8.0.v201206081200", "3.8.0.v20120521-2346", null), // JUNO_3_8_WITH_PLATFORM(SDK_PRODUCT_ID, JUNO_3_8.productVersion(), JUNO_3_8.runtimeVersion(), "3.8.0.v201206081200"), // JUNO(JAVA_PRODUCT_ID, "1.5.0.20120131-1544", "3.8.0.v20120521-2346", null), // JUNO_WITH_PLATFORM(JAVA_PRODUCT_ID, JUNO.productVersion(), JUNO.runtimeVersion(), "4.2.0.v201206081400"), // JUNO_SR2(JAVA_PRODUCT_ID, "1.5.2.20130110-1126", "3.8.0.v20120521-2346", "4.2.2.v201302041200"), // KEPLER(JAVA_PRODUCT_ID, "2.0.0.20130613-0530", "3.9.0.v20130326-1255", "4.3.0.v20130605-2000"), // KEPLER_SR2(JAVA_PRODUCT_ID, "2.0.2.20140224-0000", "3.9.100.v20131218-1515", "4.3.2.v20140221-1700"), // LUNA(JAVA_PRODUCT_ID, "4.4.0.20140612-0500", "3.10.0.v20140318-2214", "4.4.0.v20140606-1215"), // LUNA_SR2(JAVA_PRODUCT_ID, "4.4.2.20150219-0708", "3.10.0.v20140318-2214", "4.4.2.v20150204-1700"), // MARS(JAVA_PRODUCT_ID, "4.5.0.20150326-0704", "3.10.0.v20150112-1422", "4.5.0.v20150203-1300"); private final String productId; private final String productVersion; private final String runtimeVersion; private final String platformVersion; private EclipseRelease(String productId, String productVersion, String runtimeVersion, String platformVersion) { this.productId = productId; this.productVersion = productVersion; this.runtimeVersion = runtimeVersion; this.platformVersion = platformVersion; } private EclipseRelease(String productVersion, String runtimeVersion, String platformVersion) { this(JAVA_PRODUCT_ID, productVersion, runtimeVersion, platformVersion); } public String productId() { return productId; } public String productVersion() { return productVersion; } public String runtimeVersion() { return runtimeVersion; } public String platformVersion() { return platformVersion; } public void applyTo(Map<String, String> metaParams) { if (productVersion == null) { metaParams.remove(DefaultMarketplaceService.META_PARAM_PRODUCT); metaParams.remove(DefaultMarketplaceService.META_PARAM_PRODUCT_VERSION); } else { metaParams.put(DefaultMarketplaceService.META_PARAM_PRODUCT, productId); metaParams.put(DefaultMarketplaceService.META_PARAM_PRODUCT_VERSION, productVersion); } if (runtimeVersion == null) { metaParams.remove(DefaultMarketplaceService.META_PARAM_RUNTIME_VERSION); } else { metaParams.put(DefaultMarketplaceService.META_PARAM_RUNTIME_VERSION, runtimeVersion); } if (platformVersion == null) { metaParams.remove(DefaultMarketplaceService.META_PARAM_PLATFORM_VERSION); } else { metaParams.put(DefaultMarketplaceService.META_PARAM_PLATFORM_VERSION, platformVersion); } } public static EclipseRelease previous(EclipseRelease release) { if (release == UNKNOWN) { return null; } int previousOrdinal = release.ordinal() - 1; return previousOrdinal > UNKNOWN.ordinal() ? values()[previousOrdinal] : null; } public static EclipseRelease next(EclipseRelease release) { if (release == UNKNOWN) { return null; } int nextOrdinal = release.ordinal() + 1; return values().length > nextOrdinal ? values()[nextOrdinal] : null; } } public static enum Solution { JUNO("test-entry-juno", EclipseRelease.JUNO_3_8, EclipseRelease.JUNO_SR2), // KEPLER("test-entry-kepler", EclipseRelease.KEPLER, EclipseRelease.KEPLER_SR2), // LUNA("test-entry-luna", EclipseRelease.LUNA, EclipseRelease.LUNA_SR2), // MARS("test-entry-mars", EclipseRelease.MARS, EclipseRelease.MARS), // JUNO_AND_EARLIER("test-entry-juno-and-earlier", null, EclipseRelease.JUNO_SR2), // KEPLER_AND_EARLIER("test-entry-kepler-and-earlier", null, EclipseRelease.KEPLER_SR2), // KEPLER_LUNA("test-entry-kepler-luna", EclipseRelease.KEPLER, EclipseRelease.LUNA_SR2), // KEPLER_MARS("test-entry-kepler-luna-mars", EclipseRelease.KEPLER, EclipseRelease.MARS), // LUNA_WIN32("test-entry-luna-win32", EclipseRelease.LUNA, EclipseRelease.LUNA_SR2, System.WIN32), // LUNA_LINUX_MACOS("test-entry-luna-mac-linux", EclipseRelease.LUNA, EclipseRelease.LUNA_SR2, System.LINUX, System.MACOS), // MULTI_VERSION("test-entry-multi-version", null, EclipseRelease.MARS), // PSEUDO_CONFLICT("test-entry-pseudo-conflict", EclipseRelease.KEPLER, EclipseRelease.MARS), // CONFLICT("test-entry-conflict", EclipseRelease.KEPLER, EclipseRelease.MARS), // UNINSTALLABLE(""/* TODO */, null, null, System.WIN32, System.MACOS, System.LINUX); private final String id; private final String shortName; private final EclipseRelease minRelease; private final EclipseRelease maxRelease; private final System[] systems; private Solution(String shortName, EclipseRelease minRelease, EclipseRelease maxRelease, System... systems) { this.id = null; this.shortName = shortName; this.minRelease = minRelease; this.maxRelease = maxRelease; this.systems = systems; } public String id() { return id; } public String shortName() { return shortName; } public String url() { return BASE_URL + "/content/" + shortName; } public String query() { return shortName; } public boolean installable() { //TODO return true; } public EclipseRelease minRelease() { return minRelease; } public EclipseRelease maxRelease() { return maxRelease; } public System[] systems() { return systems == null || systems.length == 0 ? System.values() : systems; } public boolean isCompatible(System system) { if (systems == null || system == null) { return true; } for (System aSystem : systems()) { if (aSystem == system) { return true; } } return false; } public boolean isCompatible(EclipseRelease release) { if (release == EclipseRelease.UNKNOWN) { return true; } if (minRelease() != null) { if (minRelease().ordinal() > release.ordinal()) { return false; } } if (maxRelease() != null) { if (maxRelease().ordinal() < release.ordinal()) { return false; } } return true; } } @Parameters(name = "{index}__{0}__with__{1}_{2}") public static Iterable<Object[]> data() { List<Object[]> data = new ArrayList<Object[]>(); checkSolutionReleaseBounds(data, Solution.JUNO); checkSolutionReleaseBounds(data, Solution.KEPLER); checkSolutionReleaseBounds(data, Solution.LUNA); checkSolutionReleaseBounds(data, Solution.MARS); //bug 466627 checkSolutionWithEclipse(data, "Solution should not be installable in an older release", Solution.MARS, EclipseRelease.INDIGO, null); checkSolutionWithEclipse(data, "Solution should not be installable in an older release", Solution.MARS, EclipseRelease.JUNO_3_8, null); checkSolutionWithEclipse(data, "Solution should not be installable in an older release", Solution.MARS, EclipseRelease.JUNO, null); checkSolutionReleaseBounds(data, Solution.JUNO_AND_EARLIER); checkSolutionReleaseBounds(data, Solution.KEPLER_AND_EARLIER); checkSolutionReleaseBounds(data, Solution.KEPLER_LUNA); checkSolutionData(data, "Solution should have version 1.0.0 features for Kepler release", Solution.KEPLER_LUNA, EclipseRelease.KEPLER, System.WIN32, "1.0.0", "http://example.org/kepler", "org.example.feature.kepler"); checkSolutionData(data, "Solution should have version 1.1.0 features for Luna release", Solution.KEPLER_LUNA, EclipseRelease.LUNA, System.WIN32, "1.1.0", "http://example.org/luna", "org.example.feature.luna"); checkSolutionReleaseBounds(data, Solution.KEPLER_MARS); checkSolutionData(data, "Solution should have version 1.0.0 features for Kepler release", Solution.KEPLER_MARS, EclipseRelease.KEPLER, System.WIN32, "1.0.0", "http://example.org/kepler-luna", "org.example.feature.kepler.luna"); checkSolutionData(data, "Solution should have version 1.0.0 features for Luna release", Solution.KEPLER_MARS, EclipseRelease.LUNA, System.WIN32, "1.0.0", "http://example.org/kepler-luna", "org.example.feature.kepler.luna"); checkSolutionData(data, "Solution should have version 1.1.0 features for Mars release", Solution.KEPLER_MARS, EclipseRelease.MARS, System.WIN32, "1.1.0", "http://example.org/mars", "org.example.feature.mars"); checkSolutionWithEclipse(data, "Solution should be installable in a compatible release and os", Solution.LUNA_WIN32, EclipseRelease.LUNA, System.WIN32); checkSolutionWithEclipse(data, "Solution should not be installable in an incompatible os", Solution.LUNA_WIN32, EclipseRelease.LUNA, System.LINUX); checkSolutionWithEclipse(data, "Solution should not be installable in an older release", Solution.LUNA_WIN32, EclipseRelease.KEPLER, System.WIN32); checkSolutionWithEclipse(data, "Solution should not be installable in an older release and incompatible os", Solution.LUNA_WIN32, EclipseRelease.KEPLER, System.LINUX); checkSolutionWithEclipse(data, "Solution should not be installable in a newer release", Solution.LUNA_WIN32, EclipseRelease.MARS, System.WIN32); checkSolutionWithEclipse(data, "Solution should not be installable in a newer release and incompatible os", Solution.LUNA_WIN32, EclipseRelease.MARS, System.LINUX); checkSolutionWithEclipse(data, "Solution should be installable in a compatible release and os", Solution.LUNA_LINUX_MACOS, EclipseRelease.LUNA, System.LINUX); checkSolutionWithEclipse(data, "Solution should be installable in a compatible release and os", Solution.LUNA_LINUX_MACOS, EclipseRelease.LUNA, System.MACOS); checkSolutionWithEclipse(data, "Solution should not installable in an incompatible os", Solution.LUNA_LINUX_MACOS, EclipseRelease.LUNA, System.WIN32); checkSolutionData(data, "Solution should have version 1.1.0 features for Juno release", Solution.MULTI_VERSION, EclipseRelease.JUNO, System.LINUX, "1.1.0", "http://example.org/juno-kepler", "org.example.feature.juno.kepler"); checkSolutionData(data, "Solution should have version 1.1.0 features for Kepler release", Solution.MULTI_VERSION, EclipseRelease.KEPLER, System.MACOS, "1.1.0", "http://example.org/juno-kepler", "org.example.feature.juno.kepler"); checkSolutionData(data, "Solution should have version 1.1.1 features for Kepler release on Windows", Solution.MULTI_VERSION, EclipseRelease.KEPLER, System.WIN32, "1.1.1", "http://example.org/juno-kepler-win32", "org.example.feature.juno.kepler.win32"); checkSolutionData(data, "Solution should have version 1.2.0 features for Luna release", Solution.MULTI_VERSION, EclipseRelease.LUNA, System.WIN32, "1.2.0", "http://example.org/luna", "org.example.feature.luna.nolinux"); checkSolutionWithEclipse(data, "Solution should be incompatible with Linux for Luna release", Solution.MULTI_VERSION, EclipseRelease.LUNA, System.LINUX, false); checkSolutionData(data, "Solution should have version 1.3.0 features for Mars release", Solution.MULTI_VERSION, EclipseRelease.MARS, System.MACOS, "1.3.0", "http://example.org/mars", "org.example.feature.mars.nolinux"); checkSolutionWithEclipse(data, "Solution should be incompatible with Linux for Mars release", Solution.MULTI_VERSION, EclipseRelease.MARS, System.LINUX, false); checkSolutionData( data, "Solution with overlapping versions but separate os (pseudo-conflict) should have version 1.0.0 for Luna on Mac", Solution.PSEUDO_CONFLICT, EclipseRelease.LUNA, System.MACOS, "1.0.0", "http://example.org/maclinux", "org.example.feature.maclinux"); checkSolutionData( data, "Solution with overlapping versions but separate os (pseudo-conflict) should have version 1.1.0 for Luna on Windows", Solution.PSEUDO_CONFLICT, EclipseRelease.LUNA, System.WIN32, "1.1.0", "http://example.org/win", "org.example.feature.win"); checkSolutionData( data, "Solution with overlapping versions (real conflict) should have correct version for non-overlapping release (older version)", Solution.CONFLICT, EclipseRelease.KEPLER, System.WIN32, "1.0.0", "http://example.org/kepler-luna", "org.example.feature.keplerluna"); checkSolutionData( data, "Solution with overlapping versions (real conflict) should have latest version for overlapping release", Solution.CONFLICT, EclipseRelease.LUNA, System.WIN32, "1.1.0", "http://example.org/luna-mars", "org.example.feature.lunamars"); checkSolutionData( data, "Solution with overlapping versions (real conflict) should have latest version for overlapping release", Solution.CONFLICT, EclipseRelease.LUNA, System.MACOS, "1.1.0", "http://example.org/luna-mars", "org.example.feature.lunamars"); checkSolutionData( data, "Solution with overlapping versions (real conflict) should have correct version for non-overlapping release (newer version)", Solution.CONFLICT, EclipseRelease.MARS, System.WIN32, "1.1.0", "http://example.org/luna-mars", "org.example.feature.lunamars"); // checkSolutionWithEclipse(data, Solution.UNINSTALLABLE, EclipseRelease.UNKNOWN, System.WIN32); // checkSolutionWithEclipse(data, Solution.UNINSTALLABLE, EclipseRelease.UNKNOWN, System.LINUX); // checkSolutionWithEclipse(data, Solution.UNINSTALLABLE, EclipseRelease.UNKNOWN, System.MACOS); return data; } private static void checkSolutionData(List<Object[]> data, String testDescription, Solution solution, EclipseRelease release, System system, String version, String site, String... features) { if (release == null) { release = EclipseRelease.UNKNOWN; } if (system == null) { system = System.WIN32; } boolean releaseCompatible = solution.isCompatible(release); boolean systemCompatible = solution.isCompatible(system); boolean compatible = releaseCompatible && systemCompatible; checkSolutionData(data, testDescription, solution, release, system, compatible, version, site, features); } private static void checkSolutionData(List<Object[]> data, String testDescription, Solution solution, EclipseRelease release, System system, boolean compatible, String version, String site, String... features) { if (release == null) { release = EclipseRelease.UNKNOWN; } if (system == null) { system = System.WIN32; } if (features != null && features.length == 0) { features = null; } for (Object[] objects : data) { if (objects[0] == solution && objects[1] == release && objects[2] == system) { if (((version == null && objects[3] == null) || (version != null && version.equals(objects[3]))) && ((site == null && objects[4] == null) || (site != null && site.equals(objects[4])))) { if (features == null && objects[5] == null) { return; } Set<String> allFeatures = new HashSet<String>(Arrays.asList(features)); Set<String> allDataFeatures = new HashSet<String>(Arrays.asList((String[]) objects[5])); if (allFeatures.equals(allDataFeatures)) { return; } } } } data.add(new Object[] { solution, release, system, version, site, features, compatible, testDescription }); } private static void checkSolutionReleaseBounds(List<Object[]> data, Solution solution) { EclipseRelease minRelease = solution.minRelease(); EclipseRelease maxRelease = solution.maxRelease(); EclipseRelease beforeMin = minRelease == null ? null : EclipseRelease.previous(minRelease); EclipseRelease afterMax = maxRelease == null ? null : EclipseRelease.next(maxRelease); if (beforeMin != null) { checkSolutionWithEclipse(data, "Solution should not be installable in an older release", solution, beforeMin, null); } for (EclipseRelease release : EclipseRelease.values()) { if (solution.isCompatible(release)) { checkSolutionWithEclipse(data, "Solution should be installable in a compatible release", solution, release, null); } } checkSolutionWithEclipse(data, "Solution should be installable in an unknown release", solution, EclipseRelease.UNKNOWN, null); if (afterMax != null) { checkSolutionWithEclipse(data, "Solution should not be installable in a newer release", solution, afterMax, null); } } private static void checkSolutionWithEclipse(List<Object[]> data, String testDescription, Solution solution, EclipseRelease release, System system) { checkSolutionData(data, testDescription, solution, release, system, null, null); } private static void checkSolutionWithEclipse(List<Object[]> data, String testDescription, Solution solution, EclipseRelease release, System system, boolean compatible) { checkSolutionData(data, testDescription, solution, release, system, compatible, null, null); } private static void assertTrue(String message, boolean b, Object... details) { Assert.assertTrue(format(message, flatten(b, details)), b); } private static void assertNotNull(Object value) { Assert.assertNotNull(value); } private static void assertEquals(String message, Object o1, Object o2, Object... details) { Assert.assertEquals(format(message, flatten(o1, o2, details)), o1, o2); } private static void assertNotNull(String message, Object value, Object... details) { Assert.assertNotNull(format(message, flatten(value, details)), value); } private static <T> void assertThat(String reason, T actual, Matcher<? super T> matcher, Object... details) { MatcherAssert.assertThat(format(reason, flatten(actual, details)), actual, matcher); } private static void assertNull(String message, Object value, Object... details) { Assert.assertNull(format(message, flatten(value, details)), value); } private static String format(String message, Object... details) { if (details == null || details.length == 0) { return message; } String contentPrefix = BASE_URL + "/content/"; for (int i = 0; i < details.length; i++) { Object detail = details[i]; if (detail instanceof INode) { INode node = (INode) detail; String url = node.getUrl(); if (url != null) { if (url.startsWith(contentPrefix)) { String shortName = url.substring(contentPrefix.length()); detail = shortName; } else { detail = url; } } else { detail = node.getId(); } } else if (detail instanceof Solution) { Solution solution = (Solution) detail; detail = solution.shortName(); } details[i] = detail; } return MessageFormat.format(message, details); } private static Object[] flatten(Object... values) { List<Object> flattened = new ArrayList<Object>(); for (Object object : values) { flatten(flattened, object); } return flattened.toArray(new Object[flattened.size()]); } private static void flatten(List<Object> flattened, Object value) { if (value instanceof Object[]) { Object[] child = (Object[]) value; for (Object object : child) { flatten(flattened, object); } } else { flattened.add(value); } } @ClassRule public static TestRule stageCredentialsRule = new ExternalResource() { private UIServices originalService; private UIServices credentialsService; @Override protected void before() throws Throwable { IProvisioningAgent agent = (IProvisioningAgent) ServiceHelper.getService(Activator.getContext(), IProvisioningAgent.SERVICE_NAME); UIServices adminUIService = (UIServices) agent.getService(UIServices.SERVICE_NAME); originalService = adminUIService; credentialsService = new UIServices() { @Override public AuthenticationInfo getUsernamePassword(String location, AuthenticationInfo previousInfo) { if (previousInfo == null) { return getUsernamePassword(location); } return null; } @Override public AuthenticationInfo getUsernamePassword(String location) { if (location != null && location.contains("marketplace-staging")) { return new AuthenticationInfo("testuser", "plaintext", false); } throw new AssertionError("Unexpectedly required authentication for host " + location); } @Override public TrustInfo getTrustInfo(Certificate[][] untrustedChain, String[] unsignedDetail) { throw new AssertionError("Unexpectedly required trustinfo"); } }; agent.registerService(UIServices.SERVICE_NAME, credentialsService); } @Override protected void after() { UIServices originalService = this.originalService; UIServices credentialsService = this.credentialsService; this.originalService = null; this.credentialsService = null; IProvisioningAgent agent = (IProvisioningAgent) ServiceHelper.getService(Activator.getContext(), IProvisioningAgent.SERVICE_NAME); Object currentUIService = agent.getService(UIServices.SERVICE_NAME); if (currentUIService == credentialsService && originalService != null) { agent.registerService(UIServices.SERVICE_NAME, originalService); } } }; @Rule public final TestRule xmlDumpRule = new TestWatcher() { private ServiceRegistration<IMarketplaceUnmarshaller> unmarshallerRegistration; @Override protected void starting(final Description description) { final IMarketplaceUnmarshaller marketplaceUnmarshaller = org.eclipse.epp.mpc.core.service.ServiceHelper .getMarketplaceUnmarshaller(); unmarshallerRegistration = MarketplaceClientCorePlugin.getDefault().getServiceHelper() .registerMarketplaceUnmarshaller(new IMarketplaceUnmarshaller() { public <T> T unmarshal(InputStream in, Class<T> type, IProgressMonitor monitor) throws UnmarshalException, IOException { byte[] input = capture(in); in = null; try { return marketplaceUnmarshaller .unmarshal(new ByteArrayInputStream(input), type, monitor); } catch (UnmarshalException ex) { dump(description, ex, input); throw ex; } catch (IOException ex) { dump(description, ex, input); throw ex; } catch (RuntimeException ex) { dump(description, ex, input); throw ex; } } private byte[] capture(InputStream in) throws IOException { try { ByteArrayOutputStream dump = new ByteArrayOutputStream(32768); byte[] buffer = new byte[8192]; for (int read = -1; (read = in.read(buffer)) != -1;) { dump.write(buffer, 0, read); } byte[] input = dump.toByteArray(); return input; } finally { in.close(); } } }); } @Override protected void finished(Description description) { if (unmarshallerRegistration != null) { unmarshallerRegistration.unregister(); } } void dump(Description description, Throwable ex, byte[] input) { String fileName = description.getDisplayName() + "_" + new SimpleDateFormat("yyyyMMdd-HHmmss").format(new Date()); fileName = safeFileName(fileName); File outputDir = findOutputDir(); File dumpFile = new File(outputDir, fileName + "-response.dump"); for (int i = 1; dumpFile.exists(); i++) { dumpFile = new File(outputDir, fileName + "_" + i + "-response.dump"); } failed(new AssertionError("Dumping XML stream to " + dumpFile.getAbsolutePath()), description); FileOutputStream os = null; try { os = new FileOutputStream(dumpFile); os.write(input); } catch (Exception e) { failed(e, description); } finally { if (os != null) { try { os.close(); } catch (IOException e) { failed(e, description); } } } } private File findOutputDir() { File targetDir = new File("target"); if (targetDir.isDirectory()) { File sureFireDir = new File(targetDir, "surefire-reports"); if (sureFireDir.isDirectory()) { return sureFireDir.getAbsoluteFile(); } return targetDir.getAbsoluteFile(); } URL resource = SolutionCompatibilityFilterTest.class.getResource("SolutionCompatibilityFilterTest.class"); if (resource != null) { try { resource = FileLocator.resolve(resource); if ("file".equalsIgnoreCase(resource.getProtocol())) { for (File file = new File(resource.toURI()); file != null && file.exists(); file = file .getParentFile()) { targetDir = new File(file, "target"); if (targetDir.isDirectory()) { File sureFireDir = new File(targetDir, "surefire-reports"); if (sureFireDir.isDirectory()) { return sureFireDir.getAbsoluteFile(); } return targetDir.getAbsoluteFile(); } } } } catch (Exception e) { } } return new File(java.lang.System.getProperty("user.dir")); } private String safeFileName(String text) { char[] fileName = text.toCharArray(); for (int i = 0; i < fileName.length; i++) { char c = fileName[i]; if (!((c >= 48 && c <= 57 /* [0-9] */) || (c >= 65 && c <= 90 /* [A-Z] */) || (c >= 97 && c <= 122 /* [a-z] */) || c == 45 /* - */|| c == 46 /* . */|| c == 95 /* _ */)) { fileName[i] = '_'; } } return new String(fileName); } }; @Rule public TestRule logRule = new TestRule() { public Statement apply(final Statement base, final Description description) { return LoggingSuite.isLogging() ? base : new Statement() { @Override public void evaluate() throws Throwable { try { log("Starting test " + description.getDisplayName()); base.evaluate(); } finally { log("Finished test " + description.getDisplayName()); } } private void log(String message) { MarketplaceClientCore.error(message, null); java.lang.System.out.println(message); } }; } }; @Rule public TestRule requestInfoRule = new TestRule() { public Statement apply(final Statement base, final Description description) { String methodName = description.getMethodName(); if (methodName.contains("SearchResult")) { return new Statement() { @Override public void evaluate() throws Throwable { try { base.evaluate(); } catch (AssertionError t) { failedSearchQuery(t, description); } } }; } else { return new Statement() { @Override public void evaluate() throws Throwable { try { base.evaluate(); } catch (AssertionError t) { failedNodeQuery(t, description); } } }; } } protected void failedSearchQuery(AssertionError error, Description description) { String request = marketplaceService.addMetaParameters(BASE_URL + "/" + DefaultMarketplaceService.API_SEARCH_URI_FULL + solution.query()); String queryDetail = "Unexpected result in search for node " + solution.shortName() + "\n " + request; failedWithDetails(error, queryDetail); } protected void failedNodeQuery(AssertionError error, Description description) { String queryDetail = "Unexpected result in query for node " + solution.shortName() + "\n " + marketplaceService.addMetaParameters(solution.url() + "/api/p"); failedWithDetails(error, queryDetail); } protected void failedWithDetails(AssertionError error, String queryDetail) throws AssertionError { String message = error.getMessage() == null ? queryDetail : queryDetail + "\n\n" + error.getMessage(); String testDescription = SolutionCompatibilityFilterTest.this.testDescription; if (testDescription != null) { message = testDescription + "\n\n" + message; } throw adaptAssertionError(error, message); } protected AssertionError adaptAssertionError(AssertionError error, String message) { if (message == null || message.equals(error.getMessage())) { return error; } AssertionError newError; if (error.getClass() == AssertionError.class) { newError = new AssertionError(message); } else if (error.getClass() == ComparisonFailure.class) { ComparisonFailure comparisonFailure = (ComparisonFailure) error; newError = new ComparisonFailure(message, comparisonFailure.getExpected(), comparisonFailure .getActual()); } else { newError = new AssertionError(message); newError.initCause(error); } newError.setStackTrace(error.getStackTrace()); return newError; } }; @Parameter(0) public Solution solution; @Parameter(1) public EclipseRelease eclipseRelease; @Parameter(2) public System system; @Parameter(3) public String version; @Parameter(4) public String site; @Parameter(5) public String[] features; @Parameter(6) public boolean compatible; @Parameter(7) public String testDescription; private DefaultMarketplaceService marketplaceService; @Before public void setupMarketplaceService() throws Exception { marketplaceService = new DefaultMarketplaceService(new URL(BASE_URL)); marketplaceService.setRequestMetaParameters(computeRequestMetaParameters(system, eclipseRelease)); } protected Map<String, String> computeRequestMetaParameters(System system, EclipseRelease eclipseRelease) { Map<String, String> requestMetaParameters = ServiceLocator.computeDefaultRequestMetaParameters(); system.applyTo(requestMetaParameters); eclipseRelease.applyTo(requestMetaParameters); return requestMetaParameters; } protected INode queryNode() throws CoreException { INode node = marketplaceService.getNode(QueryHelper.nodeByUrl(solution.url()), new NullProgressMonitor()); assertNotNull("Node {0} not found", node); if (solution.id() != null) { assertEquals("Node {2} returned with wrong id {1}", solution.id(), node.getId(), solution); } if (solution.url() != null) { assertEquals("Node {2} returned with wrong url {1}", solution.url(), node.getUrl(), solution); } return node; } protected INode searchForNode() throws CoreException { ISearchResult searchResult = marketplaceService.search(null, null, solution.query(), new NullProgressMonitor()); assertSearchResultSanity(searchResult); List<? extends INode> nodes = searchResult.getNodes(); INode foundNode = null; for (INode node : nodes) { if ((solution.id() != null && solution.id().equals(node.getId())) || (solution.url() != null && solution.url().equals(node.getUrl()))) { foundNode = node; break; } } return foundNode; } protected void assertSearchResultSanity(ISearchResult result) { assertNotNull("Search result is null", result); assertNotNull("Result node list is null (internal error)", result.getNodes()); assertNotNull("Result match count is null ('count' attribute missing)", result.getMatchCount()); assertTrue("Total search result count {1} has to be at least the number of returned nodes {2}", result .getMatchCount() >= result.getNodes().size(), result.getMatchCount(), result.getNodes().size()); Set<String> ids = new HashSet<String>(); for (INode node : result.getNodes()) { assertNotNull("Search result node {1} without id", node.getId(), node); assertTrue("Duplicate search result node {1}", ids.add(node.getId()), node); } } @Test public void testNodeQuery() throws CoreException { if (compatible) { if (solution.installable()) { testCompatibleInstallableNode(); } else { testCompatibleNonInstallableNode(); } } else { testIncompatibleNode(); } } public void testCompatibleInstallableNode() throws CoreException { assumeTrue("Skipping test - this solution and Eclipse/OS are incompatible", compatible); assumeTrue("Skipping test - this solution is not installable", solution.installable()); INode node = queryNode(); String updateurl = node.getUpdateurl(); assertThat("Node {1} has no update url", updateurl, not(isEmptyOrNullString()), node); IIus ius = node.getIus(); assertNotNull("Node {1} is missing <ius> element", ius, node); List<IIu> iuElements = ius.getIuElements(); assertNotNull(iuElements); assertThat("Node {1} has no IUs", iuElements, not(empty()), node); if (version != null) { assertEquals("Node {2} has wrong version", version, node.getVersion(), node); } if (site != null) { assertEquals("Node {2} has wrong update site", site, node.getUpdateurl(), node); } if (features != null) { Set<String> allIUs = new HashSet<String>(); for (IIu iu : iuElements) { allIUs.add(iu.getId()); } assertThat("Node {1} is missing some features", allIUs, hasItems(features), node); assertThat("Node {1} has some unexpected features", allIUs, hasSize(features.length), node); } } public void testCompatibleNonInstallableNode() throws CoreException { assumeTrue("Skipping test - this solution and Eclipse/OS are incompatible", compatible); assumeFalse("Skipping test - this solution is installable", solution.installable()); INode node = queryNode(); String updateurl = node.getUpdateurl(); assertNull("Uninstallable node {1} should not have an update url, but has {0}", updateurl, node); IIus ius = node.getIus(); assertNull("Uninstallable node {1} should not have an <ius> element", ius, node); } public void testIncompatibleNode() throws CoreException { assumeFalse("Skipping test - this solution and Eclipse/OS are compatible", compatible); INode node = queryNode(); String updateurl = node.getUpdateurl(); assertNull("Incompatible node {1} should not have an update url, but has {0}", updateurl, node); IIus ius = node.getIus(); assertNull("Incompatible node {1} should not have an <ius> element", ius, node); } @Test public void testSearchResult() throws CoreException { if (compatible) { testCompatibleSearchResult(); } else { testIncompatibleSearchResult(); } } public void testCompatibleSearchResult() throws CoreException { assumeTrue("Skipping test - this solution and Eclipse/OS are incompatible", compatible); INode foundNode = searchForNode(); assertNotNull("Compatible node {1} not found in search", foundNode, solution); } public void testIncompatibleSearchResult() throws CoreException { assumeFalse("Skipping test - this solution and Eclipse/OS are compatible", compatible); INode foundNode = searchForNode(); assertNull("Incompatible node {0} found in search", foundNode); } }